package cn.ctyun.ipush.utils;

import cn.ctyun.ipush.exceptions.ScheduleException;
import cn.ctyun.ipush.model.ScheduleJob;
import cn.ctyun.ipush.model.TaskDetailModel;
import cn.ctyun.ipush.quartz.JobExecutor;
import cn.ctyun.ipush.quartz.JobSyncFactory;
import cn.ctyun.ipush.vo.ScheduleJobVo;
import cn.ctyun.ipush.vo.TaskVo;
import com.dexcoder.commons.utils.UUIDUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 定时任务辅助类
 * <p/>
 * Created by liyd on 12/19/14.
 */
public class ScheduleUtils {


    /**
     * 日志对象
     */
    private static final Logger LOG = LoggerFactory.getLogger(ScheduleUtils.class);

    /**
     * 获取触发器key
     *
     * @param jobName
     * @param jobGroup
     * @return
     */
    public static TriggerKey getTriggerKey(String jobName, String jobGroup) {

        return TriggerKey.triggerKey(jobName, jobGroup);
    }

    /**
     * 获取表达式触发器
     *
     * @param scheduler the scheduler
     * @param jobName   the job name
     * @param jobGroup  the job group
     * @return cron trigger
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, String jobName, String jobGroup) {

        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            return (CronTrigger) scheduler.getTrigger(triggerKey);
        } catch (SchedulerException e) {
            LOG.error("获取定时任务CronTrigger出现异常", e);
            throw new ScheduleException("获取定时任务CronTrigger出现异常");
        }
    }

    /**
     * 创建任务
     *
     * @param scheduler   the scheduler
     * @param scheduleJob the schedule job
     */
//    public static void createScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) {
//        createScheduleJob(scheduler, scheduleJob.getJobName(), scheduleJob.getJobGroup(),
//                scheduleJob.getCronExpression(), scheduleJob.getIsSync(), scheduleJob);
//    }

    /**
     * 创建定时任务
     *
     * @param scheduler      the scheduler
     * @param jobName        the job name
     * @param jobGroup       the job group
     * @param cronExpression the cron expression
     * @param isSync         the is sync
     * @param param          the param
     */
//    public static void createScheduleJob(Scheduler scheduler, String jobName, String jobGroup,
//                                         String cronExpression, String isSync, Object param) {
//        //同步或异步
//        Class<? extends Job> jobClass = isSync=="0" ? JobSyncFactory.class : JobFactory.class;
//
//        //构建job信息
//        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();
//
//        //放入参数，运行时的方法可以获取
//        jobDetail.getJobDataMap().put(ScheduleJobVo.JOB_PARAM_KEY, param);
//
//        //表达式调度构建器
//        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//
//        //按新的cronExpression表达式构建一个新的trigger
//        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup)
//                .withSchedule(scheduleBuilder).build();
//
//        try {
//            scheduler.scheduleJob(jobDetail, trigger);
//        } catch (SchedulerException e) {
//            LOG.error("创建定时任务失败", e);
//            throw new ScheduleException("创建定时任务失败");
//        }
//    }

    /**
     * @param scheduler
     * @param taskVo
     * @param scheduleJobVo
     */
    public synchronized static void createScheduleJob(Scheduler scheduler, TaskVo taskVo, ScheduleJobVo scheduleJobVo) {

        Long startTime = System.currentTimeMillis();
        String jobName = scheduleJobVo.getJobName();
        String jobGroup = scheduleJobVo.getJobGroup();
        String jobAliasName=scheduleJobVo.getAliasName();
        String cronExpression = scheduleJobVo.getCronExpression();
        boolean isSync = scheduleJobVo.getIsSync();
        // judge job is exist
        JobKey jobkey = new JobKey(jobName, jobGroup);
        try {
            if (scheduler.checkExists(jobkey)) {
                LOG.info("createScheduleJob: jobname,jobGroup 已经存在");
                return;
            }
        } catch (SchedulerException e) {
            LOG.info("scheduler 存在异常");
            return;
        }
        //create scheduleJob and put it to schedule
        LOG.info(String.format("----------------createScheduleJob start: jobGroup: %s ,jobName: %s ,jobAliasName:%s ----------------", jobGroup, jobName,jobAliasName));

        //同步或异步
        //Class<? extends Job> jobClass = isSync ? JobSyncFactory.class : JobFactory.class;
        Class<? extends Job> jobClass = JobExecutor.class ;

        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build();


        //jobDetail.getJobDataMap().put(ScheduleJobVo.JOB_PARAM_CONNECTIONPARAMS, connectionDescMap);
        jobDetail.getJobDataMap().put(ScheduleJobVo.JOB_PARAM_SCHEDULEJOBVO, scheduleJobVo);


        //表达式调度构建器
        Map<String, CronTrigger> cronMap = new HashMap<String, CronTrigger>();
        for (String cron : cronExpression.split("@")) {
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(trigerNameFormat(jobName, cron), jobGroup)
                    .withSchedule(scheduleBuilder).forJob(jobDetail).build();
            cronMap.put(cron, trigger);
        }
        try {
            boolean isFirst = true;
            for (CronTrigger conrtrigger : cronMap.values()) {
                if (isFirst) {
                    scheduler.scheduleJob(jobDetail, conrtrigger);
                    isFirst = false;
                } else {
                    scheduler.scheduleJob(conrtrigger);
                }
            }
            Long endTime = System.currentTimeMillis();
            LOG.info(String.format("----------------createScheduleJob  end : costTime %s ----------------", endTime - startTime));
        } catch (SchedulerException e) {
            LOG.error("创建定时任务失败", e);
            throw new ScheduleException("创建定时任务失败");
        }
    }

    /**
     * 运行一次任务
     *
     * @param scheduler
     * @param jobName
     * @param jobGroup
     */
    public static void runOnce(Scheduler scheduler, String jobName, String jobGroup) {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            LOG.error("运行一次定时任务失败", e);
            throw new ScheduleException("运行一次定时任务失败");
        }
    }

    /**
     * 暂停任务
     *
     * @param scheduler
     * @param jobName
     * @param jobGroup
     */
    public static void pauseJob(Scheduler scheduler, String jobName, String jobGroup) {

        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            LOG.error("暂停定时任务失败", e);
            throw new ScheduleException("暂停定时任务失败");
        }
    }

    /**
     * 恢复任务
     *
     * @param scheduler
     * @param jobName
     * @param jobGroup
     */
    public static void resumeJob(Scheduler scheduler, String jobName, String jobGroup) {

        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            LOG.error("暂停定时任务失败", e);
            throw new ScheduleException("暂停定时任务失败");
        }
    }

    /**
     * 获取jobKey
     *
     * @param jobName  the job name
     * @param jobGroup the job group
     * @return the job key
     */
    public static JobKey getJobKey(String jobName, String jobGroup) {

        return JobKey.jobKey(jobName, jobGroup);
    }

    /**
     * 更新定时任务
     *
     * @param scheduler   the scheduler
     * @param scheduleJob the schedule job
     */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) {
        updateScheduleJob(scheduler, scheduleJob.getJobName(), scheduleJob.getJobGroup(),
                scheduleJob.getCronExpression(), scheduleJob.getIsSync(), scheduleJob);
    }

    /**
     * 更新定时任务
     *
     * @param scheduler      the scheduler
     * @param jobName        the job name
     * @param jobGroup       the job group
     * @param cronExpression the cron expression
     * @param isSync         the is sync
     * @param param          the param
     */
    public static void updateScheduleJob(Scheduler scheduler, String jobName, String jobGroup,
                                         String cronExpression, String isSync, Object param) {

        //同步或异步
//        Class<? extends Job> jobClass = isSync ? JobSyncFactory.class : JobFactory.class;

        try {
//            JobDetail jobDetail = scheduler.getJobDetail(getJobKey(jobName, jobGroup));

//            jobDetail = jobDetail.getJobBuilder().ofType(jobClass).build();

            //更新参数 实际测试中发现无法更新
//            JobDataMap jobDataMap = jobDetail.getJobDataMap();
//            jobDataMap.put(ScheduleJobVo.JOB_PARAM_KEY, param);
//            jobDetail.getJobBuilder().usingJobData(jobDataMap);

            TriggerKey triggerKey = ScheduleUtils.getTriggerKey(jobName, jobGroup);

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder)
                    .build();

            //按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            LOG.error("更新定时任务失败", e);
            throw new ScheduleException("更新定时任务失败");
        }
    }

    /**
     * 删除定时任务
     *
     * @param scheduler
     * @param jobName
     * @param jobGroup
     */
    public static void deleteScheduleJob(Scheduler scheduler, String jobName, String jobGroup) {
        try {
            scheduler.deleteJob(getJobKey(jobName, jobGroup));
        } catch (SchedulerException e) {
            LOG.error("删除定时任务失败", e);
            throw new ScheduleException("删除定时任务失败");
        }
    }

    /**
     * cron format  1/5  *  *  *  *  ? *转换为  1/5secondd*minute*hour*day*month?week*year
     *
     * @param cron
     * @return
     */
    public static String trigerNameFormat(String jobname,String cron) {
        StringBuilder stringBuilder = new StringBuilder();
        cron = cron.trim();
        ArrayList<String> arrayList = new ArrayList();
        arrayList.add(0,"second");
        arrayList.add(1,"minute");
        arrayList.add(2,"hour");
        arrayList.add(3,"day");
        arrayList.add(4,"month");
        arrayList.add(5,"year");
        int i = 0;
        stringBuilder.append(jobname).append("_");
        for (String str : cron.split("\\s+")) {
            stringBuilder.append(str).append(arrayList.get(i++));
        }
        return stringBuilder.toString();
    }

//    public static ScheduleJobVo createScheduleJobFromTaskVo(TaskVo tv) {
//        TaskDetailModel tdm = tv.getTaskDetail();
//        ScheduleJobVo scheduleJob = new ScheduleJobVo();
//        scheduleJob.setScheduleJobId(UUIDUtils.getUUID32());
//        scheduleJob.setAutoRun(tdm.isAutoRun());
//        scheduleJob.setJobGroup(tdm.getTaskGroupName());
//        scheduleJob.setJobName(tdm.getTaskName());
//        scheduleJob.setCronExpression(tdm.getCronExpression());
//        scheduleJob.setTaskId(tv.getTaskModelId());
//        scheduleJob.setGmtCreate(DateUtils.dateToString(new Date()));
//        scheduleJob.setIsSync(false);
//        return scheduleJob;
//    }

    /**
     * get ScheduleJob from TaskVo
     *
     * @param tv
     * @return
     */
    public static ScheduleJobVo createScheduleJobFromTaskVo(TaskVo tv) {
        if(null==tv)
            return null ;
        TaskDetailModel tdm = tv.getTaskDetail();
        ScheduleJobVo scheduleJob = new ScheduleJobVo();
        scheduleJob.setScheduleJobId(UUIDUtils.getUUID32());
        scheduleJob.setIsAutoRun(tdm.getIsAutoRun());
        scheduleJob.setJobGroup(tdm.getTaskGroupName());
        scheduleJob.setJobName(tdm.getTaskName());
        scheduleJob.setAliasName(tdm.getTaskAliasName());
        scheduleJob.setCronExpression(tdm.getCronExpression());
        scheduleJob.setTaskId(tv.getTaskModelId());
        scheduleJob.setGmtCreate(DateUtils.dateToString(new Date()));
        scheduleJob.setIsSync(false);
        return scheduleJob;
    }



}
